function updateEnityDirection(enity, hude) {
	const angle = 180 - Math.floor((hude * 180 / Math.PI) % 360);
	switch(true) {
		default: 
			enity.direction = 3;
			break;
		case angle > 45 && angle <= 135:
			enity.direction = 2;
			break;
		case angle > 135 && angle <= 225:
			enity.direction = 0;
			break;
		case angle > 225 && angle <= 315:
			enity.direction = 1;
			break;
	}
}

var characterAnimations = {};
function getCharacterAnimation(state) {
	if(!characterAnimations[state])
		characterAnimations[state] = L2D.Loader.load(`res/actions/${state}.ani`);
		
	return characterAnimations[state];
}

class Character extends PIXI.Container {
	constructor() {
		super();

		this._actions = [];

		this.size = 32;
		this.frame = 0;	
		this.direction = 0;
		this._lastState = "";
		this._lastFrameTime = new Date().getTime();

		this.state = `idea`;										// 初始待机动作
		this.isCylinder = true;										// 主角是一个圆柱体
		
		// 装备
		this.equipments = [];
		for(var i = 0; i < 5; i++)
			this.equipments.push(null);

		// 基础状态
		this.level = 1;
		this.exp = 0;
		this.hp = 100;
		this.sp = 100;
		this.atk = 20;
		this.def = 5;
		this.keep = 2000;
		this.range = 0.5;
		this.weight = 10;
		this.restitution = 0.6;
		this.speed = 1;
		this.acceleration = 1.2;
		this.aspd = 1.5;
	}
	
	moveTo(target) {
		const character = this;
		const path = this.scene.findPath(this.position, target);

		// 查找当前是否存在其他move动作
		for(var i = 0; i < character._actions.length; i++) {
			const action = character._actions[i];
			if(action.constructor.name == "MoveTo") {
				character._actions.splice(i, 1);
				break;
			}
		}

		return new Promise(function(resolve) { 
				const action = new MoveTo(character, path, function(action) {
				action.deleted=true;
				resolve();
			});
			character._actions.push(action);
			return action; 
		});
	}
	
	attack() {
		if(this.state == `attack` || this.state == `hit`)
			return;

		const character = this;
		return new Promise(function(resolve) { 
				const action = new Attack(character, function(action) {
				action.deleted=true;
				resolve();
			});
			character._actions.push(action);
			return action;
		});
	}
	
 	attackTo(target) {
		const character = this;

		// 查找当前是否存在其他move动作
		for(var i = 0; i < character._actions.length; i++) {
			const action = character._actions[i];
			if(action.constructor.name == "AttackTo") {
				character._actions.splice(i, 1);
				break;
			}
		}

		return new Promise(function(resolve) { 
				const action = new AttackTo(character, target, function(action) {
				action.deleted=true;
				resolve();
			});
			character._actions.push(action);
			return action;
		});
	}
	
	talkTo(target) {
		const character = this;
		return new Promise(function(resolve) { 
				const action = new TalkTo(character, target, function(action) {
				action.deleted=true;
				resolve();
			});
			character._actions.push(action);
			return action;
		});
	}

	hurt() {
		const character = this;
		return new Promise(function(resolve) { 
				const action = new Hurt(character, function(action) {
				action.deleted=true;
				resolve();
			});
			character._actions.push(action);
			return action;
		});
	}
	
	isEnemy(target) {
		return true;
	}
	
	get centerPoint() {
		return {x:this.x,y:this.y};
	}
	
	set centerPoint(val) {
		this.x = val.x;
		this.y = val.y;
	}
	
	get state() {
		return this._lastState;
	}
	 
	set state (state) {
		// 加载对应动画包
		if(this._lastState != state) {
			this._lastState = state;
			this.frame = -1;
			this.animation = getCharacterAnimation(state);
		}
	}
	
	update() { 

		// 更新角色动作
		for(var i = this._actions.length - 1; i >= 0; i--) {
			const action = this._actions[i];
			if(action.deleted) 
			 	this._actions.splice(i, 1);
			else {
				action.update();
				break;
			}
		}

		// 更新动画帧
		if(new Date().getTime() - this._lastFrameTime > 200) {
			this._lastFrameTime = new Date().getTime();
			this.frame++; 
			if(this.animation.Frames && 
				this.frame >= this.animation.Frames.length) {

				// 检查是否存在callback
				if(this.state == "hit") {
					// 定格动画
					this.frame = this.animation.Frames.length - 1;
				}
				else {
					// 否则是循环动画
					this.frame = 0; 
				}
			}
		}
		else return;
		
		// 更新当前目标
		if(!this.Properties) return;
		if(!this.animation || !this.animation.Frames) return;
		if(this.frame >= this.animation.Frames.length) return;
		
		var drawCalls = [];
		var frameInfo = this.animation.Frames[this.frame];
		for(var i = 0; i < frameInfo.Fragments.length; i++) {
		    var frag = frameInfo.Fragments[i];
		    drawCalls.push({
		        location : frag.Locations[this.direction],
		        fragment : frag
		    });
		}
		
		drawCalls.sort(function(a,b) { 
		    return b.location.Z - a.location.Z;
		}); 
		
		while(this.children.length > 0)
			this.removeChildAt(0);
			
		for(var i = 0; i < drawCalls.length; i++) {
		    var dc = drawCalls[i];
		    var style = this.Properties.Style[dc.fragment.Folder];
		    if(style) {
		        var width = 0;
		        switch(dc.fragment.Folder) {
		            case "adornment": width = 18; break;
		            case "armor": width = 32; break;
		            case "body": width = 32; break;
		            case "bodyback": width = 32; break;
		            case "hand": width = 16; break;
		            case "head": width = 32; break;
		            case "leg": width = 16; break;
		            case "shoulder": width = 32; break; 
		            case "weapon": width = 64; break;
		            default: width = 32; break;
		        }
				
		        var halfWidth = width / 2;
		        var cc = dc.location;
		        var url = "res/role/" + dc.fragment.Folder + "/" + style;
		        var texture = PIXI.Texture.from(url);
				
				const source = new PIXI.Texture(texture, { x:width * cc.Image, y:0, width:width, height:width });
				const bunny = new PIXI.Sprite(source);
				bunny.x = cc.X - halfWidth;
				bunny.y = cc.Y - halfWidth - this.direction * 72 - 8;
				bunny.scale = this.scale;
				bunny.angle = this.angle;
				this.addChild(bunny);
		    }
		}
	}
}

function CharacterLoader(loader) {
    this.loader = loader;
}
CharacterLoader.prototype = {
    responseType : 'text',
    load : function(buffer, params, enity) {
        var jsonObj = JSON.parse(buffer);
        for(var member in jsonObj)
			enity[member] = jsonObj[member];

        return enity;
    },
    create : function() {
        return new Character(); 
    }
}

function AnimationLoader(loader) {
    this.loader = loader;
}
AnimationLoader.prototype = {
    responseType : 'text',
    load : function(buffer, params, entry) {
        var jsonObj = JSON.parse(buffer);
        for(var member in jsonObj)
            entry[member] = jsonObj[member];

        return entry;
    },
    create : function() {
        return {};
    }
}

L2D.Loader.addMode("act", new CharacterLoader(this));
L2D.Loader.addMode("ani", new AnimationLoader(this));